#include "step_definition.h"
#include <string.h>
#include <stdio.h>
#include "context_ptr.h"
#include "step.h"

using namespace CppStory;

StepDefinition::StepDefinition(std::string str, const char* f, const int l)
: pcre_handle(NULL)
, file(f)
, line(l)
, result(false)
, failed_line(0)
, cur_matched_step(NULL)
{
    const char * err_msg = NULL;
    int offset = -1;

    erase_quoting(str);
    pcre_handle = pcre_compile(regex_str.c_str(), 0, &err_msg, &offset, NULL);
    if (NULL == pcre_handle)
    {
        printf("err_msg=%s, offset=%d\n", err_msg, offset);
    }
}

StepDefinition::~StepDefinition()
{
    if (pcre_handle)
        pcre_free(pcre_handle);
}

void StepDefinition::erase_quoting(std::string s)
{
    std::string::iterator iter;
    for (iter = s.begin(); iter != s.end(); ++iter)
    {
        if ('\"' != *iter)
            regex_str += *iter;
    }
}

bool StepDefinition::match(Step* s, const char* match_str)
{
    if (NULL == pcre_handle)
        return false;

    MatchInfo match_info;
    match_info.count = pcre_exec(pcre_handle, NULL, match_str, strlen(match_str), 0, 0, match_info.ovector, OVECCOUNT);
    if (match_info.count < 0)
    {
        return false;
    }
    else
    {
        match_info.match_str = match_str;
        match_info.cur_group_index = 1;
        matched_steps[s] = match_info;
        return true;
    }
}

bool StepDefinition::run(Step* s)
{
    std::map <Step*, MatchInfo>::iterator iter;
    iter = matched_steps.find(s);
    if (iter == matched_steps.end())
        return false;

    cur_matched_step = s;
    iter->second.cur_group_index = 1;
    result = run_impl();
    step_results[s] = result;
    return result;
}

const int StepDefinition::group_count()
{
    std::map <Step*, MatchInfo>::iterator iter;
    iter = matched_steps.find(cur_matched_step);
    if (iter == matched_steps.end())
        return 0;

    return iter->second.count-1;
}

const std::string& StepDefinition::get_next_group()
{
    group_str.clear();

    std::map <Step*, MatchInfo>::iterator iter;
    iter = matched_steps.find(cur_matched_step);
    if (iter == matched_steps.end())
        return group_str;

    if (iter->second.cur_group_index > group_count())
        return group_str;
    const char *substring_start = iter->second.match_str.c_str() + iter->second.ovector[2*iter->second.cur_group_index];
    int substring_length = iter->second.ovector[2*iter->second.cur_group_index+1] - iter->second.ovector[2*iter->second.cur_group_index];

    for (int i = 0; i < substring_length; i++)
        group_str += substring_start[i];
    iter->second.cur_group_index++;
    return group_str;
}

void StepDefinition::register_context_ptr(ContextPtr *c)
{
    context_ptrs.push_back(c);
}

void StepDefinition::clean_context_ptrs()
{
    std::vector< ContextPtr* >::iterator context_ptr_iter = context_ptrs.begin();
    while (context_ptr_iter != context_ptrs.end())
    {
        (*context_ptr_iter)->clean();
#ifdef WIN32
        context_ptr_iter = context_ptrs.erase(context_ptr_iter);
#else
        context_ptrs.erase(context_ptr_iter);
#endif
    }
}

Table* StepDefinition::get_table()
{
    if (NULL == cur_matched_step)
        return NULL;
    return cur_matched_step->get_table();
}

bool StepDefinition::get_result(Step* s)
{
    std::map <Step*, bool>::iterator iter;
    iter = step_results.find(s);
    if (iter == step_results.end())
        return false;

    return step_results[s];
}

